//
//  PHDevice.m
//  PhnixHome
//
//  Created by Levy Xu on 2018/1/4.
//  Copyright © 2018年 Levy Xu. All rights reserved.
//

#import "PHDevice.h"
#import "PHLocation.h"
#import "KKUtils.h"

#define kLANInterval 5.0f
#define kWANInterval 20.0f

@interface PHDevice ()
@property(nonatomic, strong) NSMutableDictionary *points;
@property(nonatomic, strong) KKTimer *timer;
@property(nonatomic, assign) BOOL systemTimeChecked;

@property(nonatomic, strong) NSString *electricityTime;
@property(nonatomic, strong) NSMutableArray *electricities;

@property(nonatomic, strong) NSString *copTime;
@property(nonatomic, strong) NSMutableDictionary *copDict;
@end

@implementation PHDevice

+(NSArray *)mj_allowedPropertyNames {
    return @[ @"device_name", @"device_code", @"device_type", @"device_nick_name", @"is_online" ];
}

- (instancetype)init {
    self = [super init];
    if (self) {
        _points = [NSMutableDictionary dictionary];
        _electricityTime = @"";
        _electricities = [NSMutableArray array];
        _copDict = [NSMutableDictionary dictionary];
    }
    return self;
}

-(UIImage *)displayImage {
    if (_device_type == PHDeviceTypeWaterHeater) {
        return UIImageMake(@"product_waterheater1");
    }
    return nil;
}

-(NSString *)modeString {
    NSInteger mode = [self intWithCode:MODE];
    if (mode == 0) {
        return NSLocalizedString(@"dev_mode_eco", nil);
    } else if (mode == 1){
        return NSLocalizedString(@"dev_mode_fast_hot", nil);
    }
    return @"";
}

-(NSString *)displayName {
    float temp = [self floatWithCode:CURRENT_TEMP];
    return [NSString stringWithFormat:@"%@\n%@ | %.01f℃",self.device_nick_name, [self modeString], temp];
}

-(BOOL)equalTo:(PHDevice *)device {
    return [_device_code isEqualToString:device.device_code] && _device_type == device.device_type;
}

-(float)floatWithCode:(NSString *)code {
    if ([_points objectForKey:code]) {
        NSString *string = [_points objectForKey:code];
        if (!KIsBlankString(string) && [string isPureFloat]) {
            return [string floatValue];
        }
    }
    return 0;
}

-(NSInteger)intWithCode:(NSString *)code {
    if ([_points objectForKey:code]) {
        NSString *string = [_points objectForKey:code];
        if (!KIsBlankString(string) && [string mj_isPureInt]) {
            return [string integerValue];
        }
    }
    return 0;
}

#pragma mark - Timer
-(NSTimeInterval)interval {
    if ([AFNetworkReachabilityManager sharedManager].isReachableViaWiFi) {
        return kLANInterval;
    }
    return kWANInterval;
}

-(void)startTimer {
    WS(ws);
    _timer = [KKTimer every:[self interval] task:^(NSUInteger times) {
//        LOG(@"deviceID %@ times %ld",_device_code, times);
        NSMutableArray *codes = [NSMutableArray array];
        [codes addObjectsFromArray:kPointCodes_BG];
        if (ws.needDetail) {
            [codes addObjectsFromArray:kPointCodes_Detail];
        }
        if (ws.systemTimeChecked) {
            [ws request:codes animated:NO finish:nil];
        } else {
            [codes addObjectsFromArray:kPointCodes_Time];
            [ws request:codes animated:NO finish:^(BOOL success) {
                [ws checkSysTime];
            }];
        }
        [NSThread afterDelay:2.0f task:^{
            [ws getStatus:NO finish:^(BOOL success) {
                
            }];
        }];
    }];
    [_timer fire];
    
    [NNCDC addObserver:self selector:@selector(networkChanged:) name:AFNetworkingReachabilityDidChangeNotification object:nil];
}

-(void)networkChanged:(NSNotification *)notification {
    NSDictionary *userInfo = notification.userInfo;
    if ([userInfo objectForKey:AFNetworkingReachabilityNotificationStatusItem]) {
        NSInteger staus = [[userInfo objectForKey:AFNetworkingReachabilityNotificationStatusItem] integerValue];
        if (staus == AFNetworkReachabilityStatusReachableViaWiFi) {
            self.timer.interval = kLANInterval;
        } else if (staus == AFNetworkReachabilityStatusReachableViaWWAN) {
            self.timer.interval = kWANInterval;
        }
    }
}

-(void)stopTimer {
    [NNCDC removeObserver:self name:AFNetworkingReachabilityDidChangeNotification object:nil];
    if (_timer && _timer.isValid) {
        [_timer invalidate];
        _timer = nil;
    }
}

-(void)fireTimer {
    if (![_is_online isEqualToString:@"ONLINE"]) {
        [KKHUD showError:NSLocalizedString(@"tips_device_offline", nil)];
        return;
    }
    if (_timer && _timer.isValid) {
        [_timer fire];
    }
}

-(void)checkSysTime {
    NSDate *date = [NSDate date];
    LOG(@"date %zi-%zi-%zi %zi:%zi:%zi",date.year, date.month, date.day, date.hour, date.minute, date.seconds);
    NSInteger year = [self intWithCode:SYS_YEAR];
    NSInteger month = [self intWithCode:SYS_MONTH];
    NSInteger day = [self intWithCode:SYS_DAY];
    NSInteger hour = [self intWithCode:SYS_HOUR];
    NSInteger minute = [self intWithCode:SYS_MINUTE];
    if (date.year == year && date.month == month && date.day == day && date.hour == hour && date.minute == minute) {
        self.systemTimeChecked = YES;
    } else {
        WS(ws);
        NSDictionary *dict = @{ SYS_YEAR: @(date.year),
                                SYS_MONTH: @(date.month),
                                SYS_DAY: @(date.day),
                                SYS_HOUR: @(date.hour),
                                SYS_MINUTE: @(date.minute),
                                SYS_SECOND: @(date.seconds)};
        [self modify:dict animated:NO finish:^(BOOL success) {
            if (success) {
                ws.systemTimeChecked = YES;
            }
        }];
    }
}

#pragma mark - Analysis
-(NSArray *)electricityForDays:(NSInteger)days {
    if (_electricities.count == 0) {
        return nil;
    }
    //从1开始，剔除今天的数据
    NSArray *array = [_electricities subarrayWithRange:NSMakeRange(1, MIN(days, _electricities.count))];
    return [[array reverseObjectEnumerator] allObjects];
}

-(NSArray *)electricitiesThisMonth {
    NSMutableArray *array = [NSMutableArray array];
    for (PHAnalysis *elec in _electricities) {
        if ([elec.myDate isThisMonth]) {
            [array addObject:elec];
        }
    }
    return [[array reverseObjectEnumerator] allObjects];
}

-(float)electricityYestoday {
    for (PHAnalysis *elec in _electricities) {
        if ([elec.myDate isYesterday]) {
            return elec.value;
        }
    }
    return 0.0f;
}

-(float)totalElectThisMonth {
    float result = 0;
    NSArray *array = [self electricitiesThisMonth];
    for (PHAnalysis *elec in array) {
        result += elec.value;
    }
    return result;
}

-(float)copWithDate:(NSString *)date {
    if ([_copDict objectForKey:date]) {
        float cop = [[_copDict objectForKey:date] floatValue];
        if ( cop > 0) {
            return cop;
        }
    }
    return 4.0;
}

-(float)totalElectSavedThisMonth {
    float result = 0;
    NSArray *array = [self electricitiesThisMonth];
    for (PHAnalysis *elec in array) {
        float cop = [self copWithDate:elec.date];
        result += elec.value * (cop - 1);
    }
    return result;
}

-(void)getElectricityTwoMonth:(FinishBlock)finish {
    NSString *str = [[NSDate date] stringWithFormat:kYMDFormart];
    if (_electricities && [_electricityTime isEqualToString:str]) {
        !finish ?: finish(YES);
        return;
    }
    NSDate *endDate = [NSDate date];
    NSInteger lastMonth = endDate.month - 1;
    NSInteger lastYear = endDate.year;
    if (lastMonth == 0) {
        lastMonth = 12;
        lastYear -= 1;
    }
    NSString *last = [NSString stringWithFormat:@"%ld-%02ld-01",(long)lastYear, (long)lastMonth];
    NSDate *startDate = [NSDate date:last WithFormat:kYMDFormart];
    LOG(@"startDate %@ endDate %@", startDate, endDate);
    
    WS(ws);
    [self analysis:ELECTRICITY start:startDate end:endDate finish:^(NSArray *result) {
        if (result) {
            ws.electricityTime = str;
            [ws.electricities removeAllObjects];
            [ws.electricities addObjectsFromArray:result];
            //插入空值
            NSInteger days = [startDate distanceInDaysToDate:endDate] + 1;
            if (days != ws.electricities.count) {
                for (NSInteger i = 0; i < days; i++) {
                    NSDate *date = [endDate dateBySubtractingDays:i];
                    if (i < ws.electricities.count) {
                        PHAnalysis *analysis = ws.electricities[i];
                        if ([analysis.myDate isEqualToDateIgnoringTime:date]) {
                            continue;
                        }
                    }
                    PHAnalysis *analysis = [PHAnalysis zeroWithDate:date];
                    [ws.electricities insertObject:analysis atIndex:i];
                }
            }
            !finish ?: finish(YES);
        } else {
            !finish ?: finish(NO);
        }
    }];
}

-(void)getCOPThisMonth:(FinishBlock)finish {
    NSString *str = [[NSDate date] stringWithFormat:kYMDFormart];
    if (_copDict && [_copTime isEqualToString:str]) {
        !finish ?: finish(YES);
        return;
    }
    NSDate *endDate = [NSDate date];
    NSInteger lastMonth = endDate.month;
    NSInteger lastYear = endDate.year;
    NSString *last = [NSString stringWithFormat:@"%ld-%02ld-01",(long)lastYear, (long)lastMonth];
    NSDate *startDate = [NSDate date:last WithFormat:kYMDFormart];
    LOG(@"startDate %@ endDate %@", startDate, endDate);
    
    WS(ws);
    [self analysis:COP start:startDate end:endDate finish:^(NSArray *result) {
        if (result) {
            ws.copTime = str;
            [ws.copDict removeAllObjects];
            for (PHAnalysis *analysis in result) {
                if (!KIsBlankString(analysis.date)) {
                    [ws.copDict setObject:@(analysis.value) forKey:analysis.date];
                }
            }
            !finish ?: finish(YES);
        } else {
            !finish ?: finish(NO);
        }
    }];
}

#pragma mark - Networking
-(void)modifyNickname:(NSString *)nickname finish:(FinishBlock)finish {
    NSDictionary *parameters = @{ @"device_code": _device_code, @"device_nick_name": nickname };
    LOG(@"parameters %@",parameters);
    
    [KKHUD showLoading:NSLocalizedString(@"modify_nickname", nil)];
    [[NetUtils JSONManager] POST:@"device/updateDevice.json" parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        CommonResult *result = [CommonResult mj_objectWithKeyValues:[responseObject mj_JSONObject]];
        LOG(@"responseObject %@",responseObject);
        if (result && result.is_result_suc) {
            [KKHUD showSucceed:NSLocalizedString(@"tips_success", nil)];
            !finish ?: finish(YES);
        } else {
            [KKHUD showError:result.error_msg];
            !finish ?: finish(NO);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        LOG(@"error %@",error.description);
        [KKHUD showError:NSLocalizedString(@"tips_network_error", nil)];
        !finish ?: finish(NO);
    }];
}


-(void)bind:(FinishBlock)finish {
    NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
    [parameters setObject:APP_DELEGATE.token.user_id forKey:@"user_id"];
    [parameters setObject:_device_code forKey:@"device_code"];
    [parameters setObject:[NSString stringWithFormat:@"%ld",(long)_device_type] forKey:@"device_type"];
    if (_device_nick_name) {
        [parameters setObject:_device_nick_name forKey:@"device_nick_name"];
    }
    
    [KKHUD showLoading:NSLocalizedString(@"tips_waiting", nil)];
    [GPHLocation locationWithBlock:^(CLPlacemark *placemark) {
        if (placemark) {
            NSString *county = placemark.subLocality;
            NSString *address = [NSString stringWithFormat:@"%@ %@ %@ %@ %@",placemark.country, placemark.administrativeArea, placemark.locality, placemark.subLocality, placemark.name];
            LOG(@"address %@",address);
            [parameters setObject:county forKey:@"county"];
            [parameters setObject:address forKey:@"address"];
        }
        LOG(@"parameters %@",parameters);
        [[NetUtils JSONManager] POST:@"device/bound.json" parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            CommonResult *result = [CommonResult mj_objectWithKeyValues:[responseObject mj_JSONObject]];
            LOG(@"responseObject %@",responseObject);
            if (result && result.is_result_suc) {
                [KKHUD showSucceed:NSLocalizedString(@"tips_success", nil)];
                !finish ?: finish(YES);
            } else {
                [KKHUD showError:result.error_msg];
                !finish ?: finish(NO);
            }
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            LOG(@"error %@",error.description);
            [KKHUD showError:NSLocalizedString(@"tips_network_error", nil)];
            !finish ?: finish(NO);
        }];
    }];
}


-(void)unbind:(FinishBlock)finish {
    NSDictionary *parameters = @{ @"device_code": _device_code };
    LOG(@"parameters %@",parameters);
    [KKHUD showLoading:NSLocalizedString(@"tips_waiting", nil)];
    [[NetUtils JSONManager] POST:@"device/unbound.json" parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        CommonResult *result = [CommonResult mj_objectWithKeyValues:[responseObject mj_JSONObject]];
        LOG(@"responseObject %@",responseObject);
        if (result && result.is_result_suc) {
            [KKHUD showSucceed:NSLocalizedString(@"tips_success", nil)];
            !finish ?: finish(YES);
        } else {
            [KKHUD showError:result.error_msg];
            !finish ?: finish(NO);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        LOG(@"error %@",error.description);
        [KKHUD showError:NSLocalizedString(@"tips_network_error", nil)];
        !finish ?: finish(NO);
    }];
}


-(void)request:(NSArray *)array animated:(BOOL)animated finish:(FinishBlock)finish {
    
    NSAssert(array, @"protocal_codes cannot be null");
    
    if (![_is_online isEqualToString:@"ONLINE"]) {
        if (animated) [KKHUD showError:NSLocalizedString(@"tips_device_offline", nil)];
        !finish ?: finish(NO);
        return;
    }
    
    WS(ws);
    NSDictionary *parameters = @{ @"device_code": _device_code, @"protocal_codes": array };
//    LOG(@"parameters %@",parameters);
    if (animated) [KKHUD showLoading:NSLocalizedString(@"tips_waiting", nil)];
    [[NetUtils JSONManager] POST:@"device/getDataByCode.json" parameters:parameters progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        CommonResult *result = [CommonResult mj_objectWithKeyValues:[responseObject mj_JSONObject]];
//        LOG(@"responseObject %@",responseObject);
        if (result.is_result_suc) {
            if (animated) [KKHUD showSucceed:NSLocalizedString(@"tips_success", nil)];
            for (NSDictionary *dict in result.object_result) {
                if ([dict objectForKey:@"code"] && [dict objectForKey:@"value"]) {
                    NSString *code = [dict objectForKey:@"code"];
                    NSString *value = [dict objectForKey:@"value"];
                    [ws.points setObject:value forKey:code];
                }
            }
//            LOG(@"points %@", ws.points);
            [NNCDC postNotificationName:kDeviceStatusChangedNotification object:ws];
            !finish ?: finish(YES);
        } else {
            if (animated) [KKHUD showError:result.error_msg];
            !finish ?: finish(NO);
        }
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        LOG(@"error %@",error.description);
        if (animated) [KKHUD showError:NSLocalizedString(@"tips_network_error", nil)];
        !finish ?: finish(NO);
    }];
}

-(void)getStatus:(BOOL)animated finish:(FinishBlock)finish {
    WS(ws);
    NSDictionary *parameters = @{ @"device_code": _device_code };
//    LOG(@"parameters %@",parameters);
    if (animated) [KKHUD showLoading:NSLocalizedString(@"tips_waiting", nil)];
    [[NetUtils JSONManager] POST:@"device/getDeviceStatus.json" parameters:parameters progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        CommonResult *result = [CommonResult mj_objectWithKeyValues:[responseObject mj_JSONObject]];
//        LOG(@"responseObject %@",responseObject);
        if (result.is_result_suc) {//UNFINDED、 ONLINE、UNACTIVE、 OFFLINE
            if (animated) [KKHUD showSucceed:NSLocalizedString(@"tips_success", nil)];
            NSDictionary *dict = [result object_result];
            ws.is_online = [dict objectForKey:@"status"];
//            LOG(@"status %@", ws.is_online);
            [NNCDC postNotificationName:kDeviceStatusChangedNotification object:ws];
            !finish ?: finish(YES);
        } else {
            LOG(@"error_msg %@", result.error_msg);
            if (animated) [KKHUD showError:result.error_msg];
            !finish ?: finish(NO);
        }
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        LOG(@"error %@",error.description);
        if (animated) [KKHUD showError:NSLocalizedString(@"tips_network_error", nil)];
        !finish ?: finish(NO);
    }];
}

-(void)modify:(NSDictionary *)dict animated:(BOOL)animated finish:(FinishBlock)finish {
    if (![_is_online isEqualToString:@"ONLINE"]) {
        if (animated) [KKHUD showError:NSLocalizedString(@"tips_device_offline", nil)];
        !finish ?: finish(NO);
        return;
    }
    NSMutableArray *param = [NSMutableArray array];
    for (NSString *key in dict.allKeys) {
        NSDictionary *point = @{ @"device_code": _device_code, @"protocol_code": key, @"value": [dict[key] stringValue] };
        [param addObject:point];
    }
    NSDictionary *parameters = @{ @"param": param };
    
    LOG(@"parameters %@",parameters);
    if (animated) [KKHUD showLoading:NSLocalizedString(@"tips_waiting", nil)];
    [[NetUtils JSONManager] POST:@"device/control.json" parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        CommonResult *result = [CommonResult mj_objectWithKeyValues:[responseObject mj_JSONObject]];
        LOG(@"responseObject %@",responseObject);
        if (result && result.is_result_suc) {
            if (animated) [KKHUD showSucceed:NSLocalizedString(@"tips_success", nil)];
            !finish ?: finish(YES);
        } else {
            if (animated) [KKHUD showError:result.error_msg];
            !finish ?: finish(NO);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        LOG(@"error %@",error.description);
        if (animated) [KKHUD showError:NSLocalizedString(@"tips_network_error", nil)];
        !finish ?: finish(NO);
    }];
}

-(void)analysis:(NSString *)code start:(NSDate *)start end:(NSDate *)end finish:(void (^)(NSArray *result))finish {
    NSString *startString = [start stringWithFormat:kYMDFormart];
    NSString *endString = [end stringWithFormat:kYMDFormart];
    NSDictionary *parameters = @{ @"device_code": _device_code, @"protocol_code": code, @"start_date": startString, @"end_date": endString };
    LOG(@"parameters %@",parameters);
    [[NetUtils JSONManager] POST:@"device/analysis.json" parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        CommonResult *result = [CommonResult mj_objectWithKeyValues:[responseObject mj_JSONObject]];
        LOG(@"responseObject %@",responseObject);
        if (result && result.is_result_suc) {
            NSArray *array = [PHAnalysis mj_objectArrayWithKeyValuesArray:result.object_result];
            !finish ?: finish(array);
        } else {
            [KKHUD showError:result.error_msg];
            !finish ?: finish(nil);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        LOG(@"error %@",error.description);
        !finish ?: finish(nil);
    }];
}

@end
